import os, sys

import wx
import wx.glcanvas

import osg, osgDB, osgGA, osgViewer

from OSGHandler import OSGHandler





def createTelepointer(subcontroller, width, height):             
    hudCamera = osg.Camera()
    hudCamera.setProjectionMatrixAsOrtho2D(0, width, 0, height)
    hudCamera.setViewMatrix(osg.Matrixd.identity())
    hudCamera.setReferenceFrame(osg.Camera.ABSOLUTE_RF)
    hudCamera.setRenderOrder(osg.Camera.POST_RENDER)
    hudCamera.setClearMask(osg.GL_DEPTH_BUFFER_BIT)
    hudCamera.getOrCreateStateSet().setMode(osg.GL_LIGHTING, osg.GL_FALSE)
    hudCamera.__disown__()
    return hudCamera


class OSGFrame(wx.Frame):
    def __init__(self, subcontroller, filename, parent, id, title):
        wx.Frame.__init__( self, parent, id, title, size=(600, 400),
                           style=wx.DEFAULT_FRAME_STYLE | wx.FULL_REPAINT_ON_RESIZE )
        
        self.subcontroller = subcontroller
        
        self.Bind(wx.EVT_IDLE, self.OnIdle)
        
        self.Bind(wx.EVT_CLOSE, self.subcontroller.OnFrameClose, self)
        
        width,height = self.GetClientSize()
        self.canvas = OSGCanvas(self, wx.ID_ANY, 0, 0, width, height)
        
        root = osg.Switch()
        
        model = osgDB.readNodeFile( filename.encode() )
        telepointer = createTelepointer(subcontroller, 600, 400)
        
        self.subcontroller.rootNode = root
        self.subcontroller.telepointerNode = telepointer
        self.subcontroller.modelNode = model
    
        root.addChild( model )
        root.addChild( telepointer, False )
        
        
#        # create the 3D telepointer
#        camera = osg.Camera()
##        camera.setProjectionMatrixAsOrtho2D(0, 600, 0, 400)
##        camera.setViewMatrix(osg.Matrixd.identity())
##        camera.setReferenceFrame(osg.Camera.ABSOLUTE_RF)
#    #    camera.setClearMask(0x00000100) # GL_DEPTH_BUFFER_BIT = 0x00000100
#        camera.getOrCreateStateSet().setMode(0x0B50, 1) # GL_LIGHTING = 0xB50, GL_FALSE = 0
##        root.addChild( camera )
#        camera.__disown__()
#        
#        pointer3D = osg.PositionAttitudeTransform()
#        scaling = osg.MatrixTransform()
#        scaling.setMatrix(  osg.Matrixd.scale( osg.Vec3(0.1, 0.1, 0.1) )  )
#        scaling.addChild( osgDB.readNodeFile('sphere.3ds') )
#        pointer3D.addChild( scaling )
#        camera.addChild( pointer3D )

        root.__disown__()
        
        self.canvas.viewer.setSceneData( root )
        
        wx.EVT_WINDOW_DESTROY(self, self.OnDestroy)
        
        self.Show()
        
        
    def OnIdle(self, evt):
        self.canvas.Refresh()
        #evt.RequestMore()
        
    def OnDestroy(self, event):
        print 'OSGViewer was destroyed'
        
        
        
        
        
        
class OSGCanvas(wx.glcanvas.GLCanvas):
    def __init__(self,parent,id,x,y,width,height):
        style = wx.WANTS_CHARS | wx.FULL_REPAINT_ON_RESIZE
        wx.glcanvas.GLCanvas.__init__(self,parent,id,wx.DefaultPosition,wx.DefaultSize,style)

        width,height = self.GetClientSize()

        self.viewer = osgViewer.Viewer()
        parent.subcontroller.viewer = self.viewer
        handler = OSGHandler( self, parent.subcontroller )
        self.viewer.addEventHandler(handler.__disown__())

        self.viewer.addEventHandler(osgViewer.StatsHandler())
        self.viewer.setCameraManipulator(MyTrackballManipulator())
#        stateSetManipulator = osgGA.StateSetManipulator()
#        getController().stateSetManipulator = stateSetManipulator
#        self.viewer.addEventHandler(stateSetManipulator)

        self.graphicswindow = self.viewer.setUpViewerAsEmbeddedInWindow(0,0,width,height)

        if self.graphicswindow.valid():

            self.old_cursor = wx.STANDARD_CURSOR

            self.Bind(wx.EVT_SIZE, self.OnSize)
            self.Bind(wx.EVT_PAINT, self.OnPaint)
            self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

            self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
            self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
            self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)


    def OnPaint(self, evt):
        wx.PaintDC(self)
        
        if (not self.GetContext() or not self.graphicswindow.valid()):
            return

        self.SetCurrent()
        self.viewer.frame()
        self.SwapBuffers()
        
#    def OnOpenFile(self, evt):
#        self.
             
        
    def OnSize(self, evt):

        w,h = self.GetClientSize()

        if self.GetParent().IsShown():
            self.SetCurrent()

        if self.graphicswindow.valid():
            self.graphicswindow.getEventQueue().windowResize(0, 0, w, h)
            self.graphicswindow.resized(0,0,w,h)

        evt.Skip()


    def OnEraseBackground(self, evt):
        pass

    def GetConvertedKeyCode(self, evt):
        """in wxWidgets, key is always an uppercase
           if shift is not pressed convert to lowercase
        """
        key = evt.GetKeyCode()
        if key >= ord('A') and key <= ord('Z'):
            if not evt.ShiftDown():
                key += 32
        return key

    def OnKeyDown(self,evt):
        key = self.GetConvertedKeyCode(evt)
        self.graphicswindow.getEventQueue().keyPress(key)
        evt.Skip()

    def OnKeyUp(self,evt):        
        key = self.GetConvertedKeyCode(evt)
        self.graphicswindow.getEventQueue().keyRelease(key)
        evt.Skip()
    

    def OnMouse(self,event):
        if (event.ButtonDown()):
            button = event.GetButton()
            self.graphicswindow.getEventQueue().mouseButtonPress(event.GetX(), event.GetY(), button)
        elif (event.ButtonUp()):
            button = event.GetButton()
            self.graphicswindow.getEventQueue().mouseButtonRelease(event.GetX(), event.GetY(), button)
        elif (event.Dragging()):
            self.graphicswindow.getEventQueue().mouseMotion(event.GetX(), event.GetY())
            pass
        elif (event.Moving()):
            self.graphicswindow.getEventQueue().mouseMotion(event.GetX(), event.GetY())
            pass
        event.Skip()
        
        
class MyTrackballManipulator(osgGA.TrackballManipulator):
    def __init__(self):
        print 'MyTrackballManipulator is created'
        osgGA.TrackballManipulator.__init__(self)
        
    def handle(*args):
        wx.MessageBox( 'Vorbei...', wx.OK | wx.ICON_EXCLAMATION )
        print 'now'
        return osgGA.TrackballManipulator.handle(*args)
    
    def className(*args):
        """className(self) -> char"""
        print 'AAA className'
        return osgGA.TrackballManipulator.className(*args)

    def setByMatrix(*args):
        """setByMatrix(self, Matrixd matrix)"""
        print 'AAA setByMatrix'
        return osgGA.TrackballManipulator.setByMatrix(*args)

    def setByInverseMatrix(*args):
        """setByInverseMatrix(self, Matrixd matrix)"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.setByInverseMatrix(*args)

    def getMatrix(*args):
        """getMatrix(self) -> Matrixd"""
        print 'AAA getMatrix'
        return osgGA.TrackballManipulator.getMatrix(*args)

    def getInverseMatrix(*args):
        """getInverseMatrix(self) -> Matrixd"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getInverseMatrix(*args)

    def getFusionDistanceMode(*args):
        """getFusionDistanceMode(self) -> osgUtil::SceneView::FusionDistanceMode"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getFusionDistanceMode(*args)

    def getFusionDistanceValue(*args):
        """getFusionDistanceValue(self) -> float"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getFusionDistanceValue(*args)

    def setNode(*args):
        """setNode(self, Node ?)"""
        print 'AAA setNode'
        return osgGA.TrackballManipulator.setNode(*args)

    def getNode(*args):
        """
        getNode(self) -> Node
        getNode(self) -> Node
        """
        print 'AAA nix'
        return osgGA.TrackballManipulator.getNode(*args)

    def home(*args):
        """
        home(self, GUIEventAdapter ea, GUIActionAdapter us)
        home(self, double ?)
        """
        print 'AAA home'
        return osgGA.TrackballManipulator.home(*args)

    def init(*args):
        """init(self, GUIEventAdapter ea, GUIActionAdapter us)"""
        print 'AAA init'
        return osgGA.TrackballManipulator.init(*args)

    def handle(*args):
        """handle(self, GUIEventAdapter ea, GUIActionAdapter us) -> bool"""
        print 'AAA handle'
        return osgGA.TrackballManipulator.handle(*args)

    def getUsage(*args):
        """getUsage(self, ApplicationUsage usage)"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getUsage(*args)

    def setMinimumZoomScale(*args):
        """setMinimumZoomScale(self, double minimumZoomScale)"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.setMinimumZoomScale(*args)

    def getMinimumZoomScale(*args):
        """getMinimumZoomScale(self) -> double"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getMinimumZoomScale(*args)

    def setCenter(*args):
        """setCenter(self, Vec3d center)"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.setCenter(*args)

    def getCenter(*args):
        """getCenter(self) -> Vec3d"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getCenter(*args)

    def setRotation(*args):
        """setRotation(self, Quat rotation)"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.setRotation(*args)

    def getRotation(*args):
        """getRotation(self) -> Quat"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getRotation(*args)

    def setDistance(*args):
        """setDistance(self, double distance)"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.setDistance(*args)

    def getDistance(*args):
        """getDistance(self) -> double"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getDistance(*args)

    def setTrackballSize(*args):
        """setTrackballSize(self, float size)"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.setTrackballSize(*args)

    def getTrackballSize(*args):
        """getTrackballSize(self) -> float"""
        print 'AAA nix'
        return osgGA.TrackballManipulator.getTrackballSize(*args)